from dataclasses import dataclass
from unicodedata import name
from bs4 import BeautifulSoup # 网页解析,获得数据
import re # 正则表达式,进行文字匹配
import urllib.request,urllib.error # 制定url获取网页数据
import json
import js2py

'''
环境:
pip install 'h5py<3.0.0' -i https://pypi.tuna.tsinghua.edu.cn/simple

说明: 
注意,传参url未必一定非得是url字符串,因为python的特性,传参数据类型是随意的,所以也可以传字典,数组;
    不过必须将字典数组转换为json字符串,且用 ### 代替 " 或 ' 号, 
    然后再接受参数的方法中用正则转义为原始字符串即可;
    
比如: 
字典 : {'name': 'comic漫漫', 'title': 'comic漫漫','age': 1}
转移为字符串: {###name###: ###comic漫漫###, ###title###: ###comic漫漫###,###age###: 1}
'''

'''
通用模块
'''
## 创建正则表达式对象
# indexComicPicture = re.compile(r'<img src="(.*?)">')
indexComicJumpurl = re.compile(r'onclick="viewComic\(\'(.*?)\'\)')
jsonRe = re.compile(r'[\r\n(\r\n)]')

## 公共方法
# 得到指定一个URL的网页内容
def askURL(url):
    head = {  # 模拟浏览器头部信息，向豆瓣服务器发送消息
        "User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 80.0.3987.122  Safari / 537.36"
    }
    # 用户代理，表示告诉豆瓣服务器，我们是什么类型的机器、浏览器（本质上是告诉浏览器，我们可以接收什么水平的文件内容）
    request = urllib.request.Request(url, headers=head)
    html = ""
    try:
        response = urllib.request.urlopen(request)
        html = response.read().decode("utf-8")
    except urllib.error.URLError as e:
        if hasattr(e, "code"):
            print(e.code)
        if hasattr(e, "reason"):
            print(e.reason)
    return html

# 处理返回结果 转换json格式, 替换换行符
def resultHandle(results):
    jsonResults = json.dumps(results).encode('utf-8').decode("unicode_escape")
    jsonResults = re.sub(jsonRe,' ', jsonResults)
    return "```" + jsonResults + "```"
'''
主要模块
'''
## 爬取首页漫画 : 爬取到首页推荐漫画对应的跳转url
'''
返回数据格式为json字符串,其中包含以下字段
title : 漫画名称
author: 作者
picture: 图片url
jumpurl: 跳转url地址
#以下字段为预留字段,非必须爬取,若未爬取将字段设置为空字符: ''
updateState: 更新状态信息: 连载中 完结
updateNum: 目前更新最新话,如果漫画已完结则爬取总集数
updateChapter: 章节名称 
type: 漫画类型
'''
def indexComic():
    # 主页网址
    baseurl = "https://manhua.dmzj.com/rank/day-block-1.shtml"
    # 解析网页
    html = askURL(baseurl)  # 保存获取到的网页源码
    soup = BeautifulSoup(html, "html.parser")
    mainContent = soup.select('.middleright-right')
    mainList = mainContent[0].find_all(class_='middlerighter', limit=10)
    # 将数据组装为json格式
    # 返回值
    results = []
    for item in mainList:
        # 通过正则匹配需要的数据
        result = {"title": "", "author": "", "picture": "","jumpurl": "", "updateState": "", "updateNum": "", "updateChapter": "", "type": ""}
        result["picture"] = str(item.img['src'])
        result["jumpurl"] = re.findall(indexComicJumpurl, str(item))[0] if len(re.findall(indexComicJumpurl, str(item))) > 0 else ""       
        # 内容一: 获取漫画名和章节信息
        contentInfo1 = item.find_all(class_='righter-mr')[0].find_all(name='a', target='_blank')
        for i in range(0,2):
            if i == 0 :
                title = ""
                title = contentInfo1[i].text
                result["title"] = title
            if i == 1 :
                updateNum = ""
                updateNum = contentInfo1[i].text
                result["updateNum"] = updateNum
        # 内容二: 获取漫画作者,连载状态,类型
        contentInfo2 = item.find_all(class_='righter-mr')[1].find_all(name='span')
        for i in range(0, 4):
            if i == 0:
                author = ""
                for item_a in contentInfo2[i].find_all(name='a', target='_blank'):
                    author = author + " " + str(item_a.text)
                result["author"] = author[1:]
            if i == 1:
                updateState = ""
                updateState = contentInfo2[i].find(name='a', target='_blank').text
                result["updateState"] = updateState
            if i == 3:
                type = ""
                for item_a in contentInfo2[i].find_all(name='a', target='_blank'):
                    type = type + " " + str(item_a.text)
                result["type"] = type[1:]
        # 添加到列表中
        results.append(result)
    return resultHandle(results)


## 根据关键字搜索漫画 : 根据关键字查询后,获取查询到的漫画的url
'''
返回数据格式为json字符串,其中包含以下字段
{
total: totalPage: 总页数 ,这里不关心每页显示条数,但是如果能控制每页显示条数的话,建议每页显示50条
data: [{
title : 漫画名称
author: 作者
picture: 图片url
jumpurl: 跳转url地址
#以下字段为预留字段,非必须爬取,若未爬取将字段设置为空字符: ''
updateState: 更新状态信息: 连载中 完结
updateNum: 目前更新最新话,如果漫画已完结则爬取总集数
updateChapter: 章节名称 
type: 漫画类型
}]
}

'''
def keywordSearch(keyword,pageSize):
    baseurl = 'https://sacg.dmzj.com/comicsum/search.php?s={keywordStr}&p={pageSizeStr}'
    # 解析网页
    # keyword.encode('unicode_escape').decode('utf-8')[2:]
    html = askURL(baseurl.format(keywordStr=urllib.parse.quote(keyword), pageSizeStr=pageSize))
    jsonHtml1 = html[len('var g_search_data = '): (len(html) - 1)]
    # print(jsonHtml1)
    jsonObject = json.loads(jsonHtml1)
    results = {"total": 1, "data":[]}
    for object in jsonObject:
        # uniHtml = html.encode('utf-8').decode("unicode_escape")
        result = {"title": "", "author": "", "picture": "","jumpurl": "", "updateState": "", "updateNum": "", "updateChapter": "", "type": ""}
        result["title"] = str(object["comic_name"])
        result["author"] = str(object["comic_author"]).replace('/', ' ')
        result["picture"] = str(object["comic_cover"])
        result["jumpurl"] = str(object["comic_url"]).replace('//', 'https://')
        result["updateState"] = "连载中" if str(object["status"]).strip() == "" else "已完结"
        result["updateNum"] = str(object["last_update_chapter_name"])
        results["data"].append(result)
    
    return resultHandle(results)


## 检索某一部漫画的详细信息 : 根据url,来获取到漫画的章节详细信息
'''
返回数据格式为json字符串,其中包含以下字段
title : 漫画名称
author: 作者
picture: 图片url
describe: 漫画简介
#以下字段为预留字段,非必须爬取,若未爬取将字段设置为空字符: ''
updateState: 更新状态信息: 连载中 完结
updateNum: 目前更新最新话,如果漫画已完结则爬取总集数
type: 漫画类型
country: 国家
total: 章节总页数  
chapterInfo: [
    {
        'chapterName': 章节名称
        'chapterUrl': 章节转跳url
    }
]
'''
def chapterInfoComic(baseurl,pageIndex):
    firstUrl = 'https://manhua.dmzj.com'
    html = askURL(baseurl)
    soup = BeautifulSoup(html, "html.parser")
    comicInfoHtml = soup.find_all(name='div', class_='week_mend_back')[0]
    allChapterHtmlOther = soup.find_all(name='div', class_='cartoon_online_border_other')
    allChapterHtml = soup.find_all(name = 'div',class_='cartoon_online_border')
    describeHtml = soup.find(class_='line_height_content')
    resultChapterInfo = []
    results = {'title': '', 'author': '', 'picture': '', 'updateState': '', 'updateNum': '', 'type': '','describe': '','country': '','total': '','chapterInfo': resultChapterInfo}
    # 获取漫画章节
    for chapterHtml in allChapterHtmlOther:
        for item in chapterHtml.select('a'):
            chapterinfo = {'chapterName': '', 'chapterUrl': ''}
            chapterinfo['chapterUrl'] = str(firstUrl + item['href'])
            chapterinfo['chapterName'] = str(item.text)
            resultChapterInfo.append(chapterinfo)
    for chapterHtml in allChapterHtml:
        for item in chapterHtml.select('a'):
            chapterinfo = {'chapterName': '','chapterUrl': ''}
            chapterinfo['chapterUrl'] = str(firstUrl + item['href'])
            chapterinfo['chapterName'] = str(item.text)
            resultChapterInfo.append(chapterinfo)
    # 获取漫画基本信息
    for baseinfo in comicInfoHtml.find_all('tr'):
        if baseinfo.th.text.strip() == '作者：':
            results["author"] = baseinfo.td.text
        if baseinfo.th.text == '地域：':
            results["country"] = baseinfo.td.text
        if baseinfo.th.text == '状态：':
            results["updateState"] = baseinfo.td.text
        if baseinfo.th.text == '题材：':
            for item in baseinfo.find_all('a'):
                results["type"] = results["type"] + " " + item.text
            results["type"] = results["type"][1:]
        if baseinfo.th.text == '最新收录：':
            results["updateNum"] = baseinfo.a.text
    results["picture"] = comicInfoHtml.img['src']
    results["title"] = comicInfoHtml.img['alt']
    results["describe"] = describeHtml.text.strip()
    # 总页数: 因为可以一次性获取全部数据,所以只有一页 ; 
    results['total'] = 1
    return resultHandle(results)

## 检索某一部漫画的具体某一章节的所有图片 : 爬取漫画章节的url,获取详细的图片路径
'''
返回数据格式为json字符串,其中包含以下字段
title : 漫画名称
pictureUrl: ['',''] 图片url
nextChapterUrl: 下一话章节url
nextName: 下一章节名称
previousChapterUrl: 上一话章节url
previousName: 上一章节名称
# 非必须字段
chapterUrl : 漫画详细信息url
'''
def pictureInfoComic(baseurl):
    firstUrl = 'https://manhua.dmzj.com'
    comicUrl = 'http://images.dmzj.com/'
    html = askURL(baseurl)
    soup = BeautifulSoup(html, "html.parser")
    jsString = soup.find('script')
    titleInfo = soup.find(class_='hotrmtexth1')
    nextPrevious = soup.find_all(class_='display_graybg')[1]
    pictureUrl = []
    results = {'title': '', 'chapterUrl': '', 'nextChapterUrl': '', 'nextName': '','previousChapterUrl': '', 'previousName': '','pictureUrl': pictureUrl}
    # 获取标题信息 和 漫画详细信息url
    results['title'] = titleInfo.a.text
    results['chapterUrl'] = firstUrl + titleInfo.a['href']
    # 获取下一章节 上一章节信息
    results["previousChapterUrl"] = results['chapterUrl'] + nextPrevious.find(class_='display_left').a['href']
    results["previousName"] = nextPrevious.find(class_='display_left').a.text
    results["nextChapterUrl"] = results['chapterUrl'] + nextPrevious.find(class_='display_right').a['href']
    results["nextName"] = nextPrevious.find(class_='display_right').a.text
    # 获取图片
    js = js2py.EvalJs()
    js.execute(jsString.text)
    for i in js.arr_pages:
        pictureUrl.append(comicUrl + i)
    return resultHandle(results)

'''
main模块
'''
### 主方法,根据命令行传递的参数来执行不同的内容
if __name__ == "__main__":
    '''1'''
    # print(str(indexComic()))
    '''2'''
    # print(keywordSearch('你', 1))
    '''3'''
    # baseurl1 = 'http://manhua.dmzj.com/njsjm/'
    # baseurl2 = 'https://manhua.dmzj.com/putonggongjishiquantigongjierqienengercigongjidema'
    # print(chapterInfoComic(baseurl2, 1))
    '''4'''
    # url1 = 'https://manhua.dmzj.com/putonggongjishiquantigongjierqienengercigongjidema/64616.shtml'
    # print(pictureInfoComic(url1))

